﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using NUnit.Framework;
using DomainDriver.DomainModeling.Constraints;
using DomainDriver.DomainModeling.DataProviders;
using DomainDriver.DomainModeling.DomainModels;
using DomainDriver.DomainModeling.DomainObjects;
using DomainDriver.DomainModeling.Exceptions;
using DomainDriver.DomainModeling.Repositories;

namespace DomainDriver.DomainModeling.GenericUnitTesting.Constraints
{
    public abstract class SingletonConstraintTestFixture<DOMAIN_MODEL, KEY, KEYED_DOMAIN_OBJECT> : ConstraintTestFixture<DOMAIN_MODEL, SingletonConstraint<KEY, KEYED_DOMAIN_OBJECT>>
        where DOMAIN_MODEL : class, IDomainModel
        where KEYED_DOMAIN_OBJECT : IKeyedDomainObject<KEY, KEYED_DOMAIN_OBJECT>
    {
        public SingletonConstraintTestFixture(DataSourcePersistenceType persistenceType)
            : base(persistenceType)
        { /* do nothing */}

        public SingletonConstraintTestFixture(DataSourcePersistenceType persistenceType, string constraintName)
            : base(persistenceType, constraintName)
        { /* do nothing */}

        protected virtual IRepository<KEY, KEYED_DOMAIN_OBJECT> SingletonRepository
        {
            get { return DomainModel.GetRepository<KEY, KEYED_DOMAIN_OBJECT>(); }
        }

        protected abstract KEYED_DOMAIN_OBJECT CreateSingleton();
        protected abstract void UpdateSingleton(KEYED_DOMAIN_OBJECT singleton, ref bool objectCanBeUpdated);

        [Test]
        public virtual void VerifyConstraintSetup_POSITIVE()
        {
            SaveAndReloadDomainModel();

            int expectedNumberOfObjects = 1;
            int actualNumberOfObjects = SingletonRepository.Count();

            Assert.AreEqual(expectedNumberOfObjects, actualNumberOfObjects);
        }

        [Test]
        [ExpectedException(typeof(DomainObjectManagementException))]
        public virtual void VerifyConstraintOnAddingSingleton_NEGATIVE()
        {
            SaveAndReloadDomainModel();

            KEYED_DOMAIN_OBJECT singleton = CreateSingleton();

            SingletonRepository.Add(singleton);
        }

        [Test]
        public virtual void VerifyConstraintOnUpdatingSingleton_POSITIVE()
        {
            bool objectCanBeUpdated = true;
            KEYED_DOMAIN_OBJECT originalSingleton = default(KEYED_DOMAIN_OBJECT);
            KEYED_DOMAIN_OBJECT copySingleton = default(KEYED_DOMAIN_OBJECT);
            KEYED_DOMAIN_OBJECT reloadedSingleton = default(KEYED_DOMAIN_OBJECT);

            KEY singletonKey = SingletonRepository.GetKeys().First<KEY>();

            originalSingleton = SingletonRepository.Read(singletonKey);
            copySingleton = originalSingleton.Copy();
            UpdateSingleton(originalSingleton, ref objectCanBeUpdated);
            if (objectCanBeUpdated)
            { Assert.AreNotEqual(copySingleton, originalSingleton); }
            else
            { Assert.AreEqual(copySingleton, originalSingleton); }

            SingletonRepository.Update(originalSingleton);

            SaveAndReloadDomainModel();

            reloadedSingleton = SingletonRepository.Read(singletonKey);
            Assert.AreEqual(reloadedSingleton, originalSingleton);
        }

        [Test]
        [ExpectedException(typeof(DomainObjectManagementException))]
        public virtual void VerifyConstraintOnRemovingSingleton_NEGATIVE()
        {
            SaveAndReloadDomainModel();

            KEY singletonKey = SingletonRepository.GetKeys().First<KEY>();

            SingletonRepository.Remove(singletonKey);
        }
    }
}